home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step07 / supfilesrv.c < prev    next >
Encoding:
Text File  |  1994-08-02  |  53.3 KB  |  1,902 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  *
  25. /*
  26.  * supfilesrv -- SUP File Server
  27.  *
  28.  * Usage:  supfilesrv [-l] [-P] [-N] [-R]
  29.  *    -l    "live" -- don't fork daemon
  30.  *    -P    "debug ports" -- use debugging network ports
  31.  *    -N    "debug network" -- print debugging messages for network i/o
  32.  *    -R    "RCS mode" -- if file is an rcs file, use co to get contents
  33.  *
  34.  **********************************************************************
  35.  * HISTORY
  36.  * 13-Sep-92  Mary Thompson (mrt) at Carnegie-Mellon University
  37.  *    Changed name of sup program in xpatch from /usr/cs/bin/sup to
  38.  *    /usr/bin/sup for exported version of sup.
  39.  *
  40.  * 7-July-93  Nate Williams at Montana State University
  41.  *    Modified SUP to use gzip based compression when sending files
  42.  *    across the network to save BandWidth
  43.  *
  44.  * $Log: supfilesrv.c,v $
  45.  * Revision 1.5  1993/08/04  17:46:21  brezak
  46.  * Changes from nate for gzip'ed sup
  47.  *
  48.  * Revision 1.3  1993/06/05  21:32:17  cgd
  49.  * use daemon() to put supfilesrv into daemon mode...
  50.  *
  51.  * Revision 1.2  1993/05/24  17:57:31  brezak
  52.  * Remove netcrypt.c. Remove unneeded files. Cleanup make.
  53.  *
  54.  * Revision 1.20  92/09/09  22:05:00  mrt
  55.  *     Added Brad's change to make sendfile take a va_list.
  56.  *     Added support in login to accept an non-encrypted login
  57.  *     message if no user or password is being sent. This supports
  58.  *     a non-crypting version of sup. Also fixed to skip leading
  59.  *     white space from crypts in host files.
  60.  *     [92/09/01            mrt]
  61.  * 
  62.  * Revision 1.19  92/08/11  12:07:59  mrt
  63.  *         Made maxchildren a patchable variable, which can be set by the
  64.  *         command line switch -C or else defaults to the MAXCHILDREN
  65.  *         defined in sup.h. Added most of Brad's STUMP changes.
  66.  *     Increased PGMVERSION to 12 to reflect substantial changes.
  67.  *     [92/07/28            mrt]
  68.  * 
  69.  * Revision 1.18  90/12/25  15:15:39  ern
  70.  *     Yet another rewrite of the logging code. Make up the text we will write
  71.  *        and then get in, write it and get out.
  72.  *     Also set error on write-to-full-disk if the logging is for recording
  73.  *        server is busy.
  74.  *     [90/12/25  15:15:15  ern]
  75.  * 
  76.  * Revision 1.17  90/05/07  09:31:13  dlc
  77.  *     Sigh, some more fixes to the new "crypt" file handling code.  First,
  78.  *     just because the "crypt" file is in a local file system does not mean
  79.  *     it can be trusted.  We have to check for hard links to root owned
  80.  *     files whose contents could be interpretted as a crypt key.  For
  81.  *     checking this fact, the new routine stat_info_ok() was added.  This
  82.  *     routine also makes other sanity checks, such as owner only permission,
  83.  *     the file is a regular file, etc.  Also, even if the uid/gid of th
  84.  *     "crypt" file is not going to be used, still use its contents in order
  85.  *     to cause fewer surprises to people supping out of a shared file system
  86.  *     such as AFS.
  87.  *     [90/05/07            dlc]
  88.  * 
  89.  * Revision 1.16  90/04/29  04:21:08  dlc
  90.  *     Fixed logic bug in docrypt() which would not get the stat information
  91.  *     from the crypt file if the crypt key had already been set from a
  92.  *     "host" file.
  93.  *     [90/04/29            dlc]
  94.  * 
  95.  * Revision 1.15  90/04/18  19:51:27  dlc
  96.  *     Added the new routines local_file(), link_nofollow() for use in
  97.  *     dectecting whether a file is located in a local file system.  These
  98.  *     routines probably should have been in another module, but only
  99.  *     supfilesrv needs to do the check and none of its other modules seemed
  100.  *     appropriate.  Note, the implementation should be changed once we have
  101.  *     direct kernel support, for example the fstatfs(2) system call, for
  102.  *     detecting the type of file system a file resides.  Also, I changed
  103.  *     the routines which read the crosspatch crypt file or collection crypt
  104.  *     file to save the uid and gid from the stat information obtained via
  105.  *     the local_file() call (when the file is local) at the same time the
  106.  *     crypt key is read.  This change disallows non-local files for the
  107.  *     crypt key to plug a security hole involving the usage of the uid/gid
  108.  *     of the crypt file to define who the the file server should run as.  If
  109.  *     the saved uid/gid are both valid, then the server will set its uid/gid
  110.  *     to these values.
  111.  *     [90/04/18            dlc]
  112.  * 
  113.  * Revision 1.14  89/08/23  14:56:15  gm0w
  114.  *     Changed msgf routines to msg routines.
  115.  *     [89/08/23            gm0w]
  116.  * 
  117.  * Revision 1.13  89/08/03  19:57:33  mja
  118.  *     Remove setaid() call.
  119.  * 
  120.  * Revision 1.12  89/08/03  19:49:24  mja
  121.  *     Updated to use v*printf() in place of _doprnt().
  122.  *     [89/04/19            mja]
  123.  * 
  124.  * 11-Sep-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  125.  *    Added code to record release name in logfile.
  126.  *
  127.  * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  128.  *    Added host=<hostfile> support to releases file. [V7.12]
  129.  *
  130.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  131.  *    Added crosspatch support.  Created docrypt() routine for crypt
  132.  *    test message.
  133.  *
  134.  * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  135.  *    Removed common information logging code, the quiet switch, and
  136.  *    moved samehost() check to after device/inode check.
  137.  *
  138.  * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  139.  *    Added code for "release" support. [V5.11]
  140.  *
  141.  * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
  142.  *    Added code to record final status of client in logfile. [V5.10]
  143.  *
  144.  * 22-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
  145.  *    Mergered divergent CS and ECE versions. [V5.9a]
  146.  *
  147.  * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  148.  *    Removed support for version 3 of SUP protocol.  Added changes
  149.  *    to make lint happy.  Added calls to new logging routines. [V5.9]
  150.  *
  151.  * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
  152.  *    Fixed so no password check is done when crypts are used.
  153.  *
  154.  * 25-Nov-86  Rudy Nedved (ern) at Carnegie-Mellon University
  155.  *    Set F_APPEND fcntl in logging to increase the chance
  156.  *    that the log entry from this incarnation of the file
  157.  *    server will not be lost by another incarnation. [V5.8]
  158.  *
  159.  * 20-Oct-86  Dan Nydick (dan) at Carnegie-Mellon University
  160.  *    Changed not to call okmumbles when not compiled with CMUCS.
  161.  *
  162.  * 04-Aug-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  163.  *    Added code to increment scmdebug as more -N flags are
  164.  *    added. [V5.7]
  165.  *
  166.  * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  167.  *    Renamed local variable in main program from "sigmask" to
  168.  *    "signalmask" to avoid name conflict with 4.3BSD identifier.
  169.  *    Conditionally compile in calls to CMU routines, "setaid" and
  170.  *    "logaccess". [V5.6]
  171.  *
  172.  * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  173.  *    Changed supfilesrv to use the crypt file owner and group for
  174.  *    access purposes, rather than the directory containing the crypt
  175.  *    file. [V5.5]
  176.  *
  177.  * 07-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  178.  *    Added code to keep logfiles in repository collection directory.
  179.  *    Added code for locking collections. [V5.4]
  180.  *
  181.  * 05-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  182.  *    Added code to support new FSETUPBUSY return.  Now accepts all
  183.  *    connections and tells any clients after the 8th that the
  184.  *    fileserver is busy.  New clients will retry again later. [V5.3]
  185.  *
  186.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  187.  *    Major rewrite for protocol version 4. [V4.2]
  188.  *
  189.  * 12-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  190.  *    Fixed close of crypt file to use file pointer as argument
  191.  *    instead of string pointer.
  192.  *
  193.  * 24-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  194.  *    Allow "!hostname" lines and comments in collection "host" file.
  195.  *
  196.  * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  197.  *    Don't use access() on symbolic links since they may not point to
  198.  *    an existing file.
  199.  *
  200.  * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  201.  *    Added code to restrict file server availability to when it has
  202.  *    less than or equal to eight children.
  203.  *
  204.  * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  205.  *    Merged 4.1 and 4.2 versions together.
  206.  *
  207.  * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  208.  *    Created for 4.2 BSD.
  209.  *
  210.  **********************************************************************
  211.  */
  212.  
  213. #include <libc.h>
  214. #ifdef AFS
  215. #include <afs/param.h>
  216. #undef MAXNAMLEN
  217. #endif
  218. #include <sys/param.h>
  219. #include <c.h>
  220. #include <signal.h>
  221. #include <errno.h>
  222. #include <setjmp.h>
  223. #include <pwd.h>
  224. #include <grp.h>
  225. #if __STDC__
  226. #include <stdarg.h>
  227. #else
  228. #include <varargs.h>
  229. #endif
  230. #include <sys/time.h>
  231. #include <sys/resource.h>
  232. #include <sys/wait.h>
  233. #include <sys/stat.h>
  234. #include <sys/file.h>
  235. #include <sys/dir.h>
  236. #ifdef _ABI_SOURCE
  237. #include <sys/sysmacros.h>
  238. #endif
  239. #if    MACH
  240. #include <sys/ioctl.h>
  241. #endif
  242. #if    CMUCS
  243. #include <acc.h>
  244. #include <sys/ttyloc.h>
  245. #include <access.h>
  246. #include <sys/viceioctl.h>
  247. #else    CMUCS
  248. #define ACCESS_CODE_OK        0
  249. #define ACCESS_CODE_BADPASSWORD (-2)
  250. #endif  CMUCS
  251. #include "sup.h"
  252. #define MSGFILE
  253. #include "supmsg.h"
  254.  
  255. #ifdef    lint
  256. /*VARARGS1*//*ARGSUSED*/
  257. static void quit(status) {};
  258. #endif    /* lint */
  259.  
  260. #if __STDC__
  261. void goaway (char *,...);
  262. #endif
  263.  
  264. extern int errno;
  265. long time ();
  266. uid_t getuid ();
  267.  
  268. int maxchildren;
  269.  
  270. /*
  271.  * These are used to save the stat information from the crosspatch crypt
  272.  * file or collection crypt file at the time it is opened for the crypt
  273.  * key and it is verified to be a local file.
  274.  */
  275. int runas_uid = -1;
  276. int runas_gid = -1;
  277.  
  278. #define PGMVERSION 13
  279.  
  280. /*************************
  281.  ***    M A C R O S    ***
  282.  *************************/
  283.  
  284. #define HASHBITS 8
  285. #define HASHSIZE (1<<HASHBITS)
  286. #define HASHMASK (HASHSIZE-1)
  287. #define HASHFUNC(x,y) ((x)&HASHMASK)
  288.  
  289. /*******************************************
  290.  ***    D A T A   S T R U C T U R E S    ***
  291.  *******************************************/
  292.  
  293. struct hashstruct {            /* hash table for number lists */
  294.     int Hnum1;            /* numeric keys */
  295.     int Hnum2;
  296.     char *Hname;            /* string value */
  297.     TREE *Htree;            /* TREE value */
  298.     struct hashstruct *Hnext;
  299. };
  300. typedef struct hashstruct HASH;
  301.  
  302. /*********************************************
  303.  ***    G L O B A L   V A R I A B L E S    ***
  304.  *********************************************/
  305.  
  306. char program[] = "supfilesrv";        /* program name for SCM messages */
  307. int progpid = -1;            /* and process id */
  308.  
  309. jmp_buf sjbuf;                /* jump location for network errors */
  310. TREELIST *listTL;            /* list of trees to upgrade */
  311.  
  312. int live;                /* -l flag */
  313. int dbgportsq;                /* -P flag */
  314. extern int scmdebug;            /* -N flag */
  315. extern int netfile;
  316. #ifdef RCS
  317. int candorcs;                /* -R flag */
  318. int dorcs = FALSE;
  319. #endif
  320.  
  321. char *clienthost;            /* host name of client */
  322. int nchildren;                /* number of children that exist */
  323. char *prefix;                /* collection pathname prefix */
  324. char *release;                /* collection release name */
  325. char *cryptkey;                /* encryption key if non-null */
  326. #ifdef CVS
  327. char *cvs_root;                /* RCS root */
  328. #endif
  329. char *rcs_branch;            /* RCS branch name */
  330. int lockfd;                /* descriptor of lock file */
  331.  
  332. /* global variables for scan functions */
  333. int trace = FALSE;            /* directory scan trace */
  334. int cancompress = FALSE;        /* Can we compress files */
  335. int docompress = FALSE;            /* Do we compress files */
  336.  
  337. HASH *uidH[HASHSIZE];            /* for uid and gid lookup */
  338. HASH *gidH[HASHSIZE];
  339. HASH *inodeH[HASHSIZE];            /* for inode lookup for linked file check */
  340.  
  341. char *fmttime ();            /* time format routine */
  342.  
  343. /*************************************
  344.  ***    M A I N   R O U T I N E    ***
  345.  *************************************/
  346.  
  347. main (argc,argv)
  348. int argc;
  349. char **argv;
  350. {
  351. #ifdef _ABI_SOURCE
  352.     register int x,pid;
  353.     sigset_t signalmask, oldsignalmask;
  354.     struct sigaction chldvec,ignvec,oldvec;
  355. #else
  356.     register int x,pid,signalmask;
  357.     struct sigvec chldvec,ignvec,oldvec;
  358. #endif
  359.     int chldsig ();
  360.     long tloc;
  361.  
  362.     /* initialize global variables */
  363.     pgmversion = PGMVERSION;    /* export version number */
  364.     server = TRUE;            /* export that we're not a server */
  365.     collname = NULL;        /* no current collection yet */
  366.     maxchildren = MAXCHILDREN;    /* defined in sup.h */
  367.  
  368.     init (argc,argv);        /* process arguments */
  369.  
  370. #ifdef HAS_DAEMON
  371.     if (!live)            /* if not debugging, turn into daemon */
  372.         daemon(0, 0);
  373. #endif
  374.  
  375.     logopen ("supfile");
  376.     tloc = time ((long *)NULL);
  377.     loginfo ("SUP File Server Version %d.%d (%s) starting at %s",
  378.         PROTOVERSION,PGMVERSION,scmversion,fmttime (tloc));
  379.     if (live) {
  380.         x = service ();
  381.         if (x != SCMOK)
  382.             logquit (1,"Can't connect to network");
  383.         answer ();
  384.         (void) serviceend ();
  385.         exit (0);
  386.     }
  387. #ifdef _ABI_SOURCE
  388.     ignvec.sa_handler = SIG_IGN;
  389.     sigemptyset (&(ignvec.sa_mask));
  390.     ignvec.sa_flags = 0;
  391.     (void) sigaction (SIGHUP,&ignvec,&oldvec);
  392.     (void) sigaction (SIGINT,&ignvec,&oldvec);
  393.     (void) sigaction (SIGPIPE,&ignvec,&oldvec);
  394.     chldvec.sa_handler = chldsig;
  395.     sigemptyset (&(chldvec.sa_mask));
  396.     chldvec.sa_flags = 0;
  397.     (void) sigaction (SIGCHLD,&chldvec,&oldvec);
  398. #else
  399.     ignvec.sv_handler = SIG_IGN;
  400.     ignvec.sv_onstack = 0;
  401.     ignvec.sv_mask = 0;
  402.     (void) sigvec (SIGHUP,&ignvec,&oldvec);
  403.     (void) sigvec (SIGINT,&ignvec,&oldvec);
  404.     (void) sigvec (SIGPIPE,&ignvec,&oldvec);
  405.     chldvec.sv_handler = chldsig;
  406.     chldvec.sv_mask = 0;
  407.     chldvec.sv_onstack = 0;
  408.     (void) sigvec (SIGCHLD,&chldvec,&oldvec);
  409. #endif
  410.     nchildren = 0;
  411.     for (;;) {
  412.         x = service ();
  413.         if (x != SCMOK) {
  414.             logerr ("Error in establishing network connection");
  415.             (void) servicekill ();
  416.             continue;
  417.         }
  418. #ifdef _ABI_SOURCE
  419.         sigemptyset (&signalmask);
  420.         sigaddset (&signalmask, SIGCHLD);
  421.         (void) sigprocmask (SIG_BLOCK, &signalmask, &oldsignalmask);
  422. #else
  423.         signalmask = sigblock(sigmask(SIGCHLD));
  424. #endif
  425.         if ((pid = fork()) == 0) { /* server process */
  426.             (void) serviceprep ();
  427.             answer ();
  428.             (void) serviceend ();
  429.             exit (0);
  430.         }
  431.         (void) servicekill ();    /* parent */
  432.         if (pid > 0) nchildren++;
  433. #ifdef _ABI_SOURCE
  434.         (void) sigprocmask (SIG_SETMASK, &oldsignalmask, NULL);
  435. #else
  436.         (void) sigsetmask(signalmask);
  437. #endif
  438.     }
  439. }
  440.  
  441. /*
  442.  * Child status signal handler
  443.  */
  444.  
  445. chldsig()
  446. {
  447. #ifdef _ABI_SOURCE
  448.     int w;
  449. #else
  450.     union wait w;
  451. #endif
  452.  
  453. #ifdef _ABI_SOURCE
  454.     while (waitpid((pid_t)-1, &w, WNOHANG) > 0) {
  455.         if (nchildren) nchildren--;
  456.     }
  457. #else
  458.     while (wait3(&w, WNOHANG, (struct rusage *)0) > 0) {
  459.         if (nchildren) nchildren--;
  460.     }
  461. #endif
  462. }
  463.  
  464. /*****************************************
  465.  ***    I N I T I A L I Z A T I O N    ***
  466.  *****************************************/
  467.  
  468. usage ()
  469. {
  470.     quit (1,"Usage: supfilesrv [ -l | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
  471. }
  472.  
  473. init (argc,argv)
  474. int argc;
  475. char **argv;
  476. {
  477.     register int i;
  478.     register int x;
  479.     char *clienthost,*clientuser;
  480.     char *p,*q;
  481.     char buf[STRINGLENGTH];
  482.     int maxsleep;
  483.     register FILE *f;
  484.  
  485. #ifdef RCS
  486.         candorcs = FALSE;
  487. #endif
  488.     live = FALSE;
  489.     dbgportsq = FALSE;
  490.     scmdebug = 0;
  491.     clienthost = NULL;
  492.     clientuser = NULL;
  493.     maxsleep = 5;
  494.     if (--argc < 0)
  495.         usage ();
  496.     argv++;
  497.     while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
  498.         switch (argv[0][1]) {
  499.         case 'l':
  500.             live = TRUE;
  501.             break;
  502.         case 'P':
  503.             dbgportsq = TRUE;
  504.             break;
  505.         case 'N':
  506.             scmdebug++;
  507.             break;
  508.         case 'C':
  509.             if (--argc < 1)
  510.                 quit (1,"Missing arg to -C\n");
  511.             argv++;
  512.             maxchildren = atoi(argv[0]);
  513.             break;
  514.         case 'H':
  515.             if (--argc < 3)
  516.                 quit (1,"Missing args to -H\n");
  517.             argv++;
  518.             clienthost = argv[0];
  519.             clientuser = argv[1];
  520.             cryptkey = argv[2];
  521.             argc -= 2;
  522.             argv += 2;
  523.             break;
  524. #ifdef RCS
  525.                 case 'R':
  526.                         candorcs = TRUE;
  527.                         break;
  528. #endif
  529.         default:
  530.             fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
  531.             break;
  532.         }
  533.         --argc;
  534.         argv++;
  535.     }
  536.     if (clienthost == NULL) {
  537.         if (argc != 0)
  538.             usage ();
  539.         x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
  540.         if (x != SCMOK)
  541.             quit (1,"Error in network setup");
  542.         for (i = 0; i < HASHSIZE; i++)
  543.             uidH[i] = gidH[i] = inodeH[i] = NULL;
  544.         return;
  545.     }
  546.     server = FALSE;
  547.     if (argc < 1)
  548.         usage ();
  549.     f = fopen (cryptkey,"r");
  550.     if (f == NULL)
  551.         quit (1,"Unable to open cryptfile %s\n",cryptkey);
  552.     if (p = fgets (buf,STRINGLENGTH,f)) {
  553.         if (q = index (p,'\n'))  *q = '\0';
  554.         if (*p == '\0')
  555.             quit (1,"No cryptkey found in %s\n",cryptkey);
  556.         cryptkey = salloc (buf);
  557.     }
  558.     (void) fclose (f);
  559.     x = request (dbgportsq ? DEBUGFPORT : FILEPORT,clienthost,&maxsleep);
  560.     if (x != SCMOK)
  561.         quit (1,"Unable to connect to host %s\n",clienthost);
  562.     x = msgsignon ();
  563.     if (x != SCMOK)
  564.         quit (1,"Error sending signon request to fileserver\n");
  565.     x = msgsignonack ();
  566.     if (x != SCMOK)
  567.         quit (1,"Error reading signon reply from fileserver\n");
  568.     printf ("SUP Fileserver %d.%d (%s) %d on %s\n",
  569.         protver,pgmver,scmver,fspid,remotehost());
  570.     free (scmver);
  571.     scmver = NULL;
  572.     if (protver < 7)
  573.         quit (1,"Remote fileserver does not implement reverse sup\n");
  574.     xpatch = TRUE;
  575.     xuser = clientuser;
  576.     x = msgsetup ();
  577.     if (x != SCMOK)
  578.         quit (1,"Error sending setup request to fileserver\n");
  579.     x = msgsetupack ();
  580.     if (x != SCMOK)
  581.         quit (1,"Error reading setup reply from fileserver\n");
  582.     switch (setupack) {
  583.     case FSETUPOK:
  584.         break;
  585.     case FSETUPSAME:
  586.         quit (1,"User %s not found on remote client\n",xuser);
  587.     case FSETUPHOST:
  588.         quit (1,"This host has no permission to reverse sup\n");
  589.     default:
  590.         quit (1,"Unrecognized file server setup status %d\n",setupack);
  591.     }
  592.     if (netcrypt (cryptkey) != SCMOK )
  593.         quit (1,"Running non-crypting fileserver\n");
  594.     crypttest = CRYPTTEST;
  595.     x = msgcrypt ();
  596.     if (x != SCMOK)
  597.         quit (1,"Error sending encryption test request\n");
  598.     x = msgcryptok ();
  599.     if (x == SCMEOF)
  600.         quit (1,"Data encryption test failed\n");
  601.     if (x != SCMOK)
  602.         quit (1,"Error reading encryption test reply\n");
  603.     logcrypt = CRYPTTEST;
  604.     loguser = NULL;
  605.     logpswd = NULL;
  606.     if (netcrypt (PSWDCRYPT) != SCMOK)    /* encrypt password data */
  607.         quit (1,"Running non-crypting fileserver\n");
  608.     x = msglogin ();
  609.     (void) netcrypt ((char *)NULL);    /* turn off encryption */
  610.     if (x != SCMOK)
  611.         quit (1,"Error sending login request to file server\n");
  612.     x = msglogack ();
  613.     if (x != SCMOK)
  614.         quit (1,"Error reading login reply from file server\n");
  615.     if (logack == FLOGNG)
  616.         quit (1,"%s\nImproper login to %s account\n",logerror,xuser);
  617.     xargc = argc;
  618.     xargv = argv;
  619.     x = msgxpatch ();
  620.     if (x != SCMOK)
  621.         quit (1,"Error sending crosspatch request\n");
  622.         crosspatch ();
  623.     exit (0);
  624. }
  625.  
  626. /*****************************************
  627.  ***    A N S W E R   R E Q U E S T    ***
  628.  *****************************************/
  629.  
  630. answer ()
  631. {
  632.     long starttime;
  633.     register int x;
  634. #ifdef _ABI_SOURCE
  635.     struct rlimit rl;
  636. #endif
  637.  
  638.     progpid = fspid = getpid ();
  639.     collname = NULL;
  640.     basedir = NULL;
  641.     prefix = NULL;
  642.     release = NULL;
  643.         rcs_branch = NULL;
  644. #ifdef CVS
  645.         cvs_root = NULL;
  646. #endif
  647.     goawayreason = NULL;
  648.     donereason = NULL;
  649.     lockfd = -1;
  650.     starttime = time ((long *)NULL);
  651.     if (!setjmp (sjbuf)) {
  652.         signon ();
  653.         setup ();
  654.         docrypt ();
  655.         login ();
  656.         if (xpatch) {
  657.             int fd;
  658.  
  659.             x = msgxpatch ();
  660.             if (x != SCMOK)
  661.                 exit (0);
  662.             xargv[0] = "sup";
  663.             xargv[1] = "-X";
  664.             xargv[xargc] = (char *)NULL;
  665.             (void) dup2 (netfile,0);
  666.             (void) dup2 (netfile,1);
  667.             (void) dup2 (netfile,2);
  668. #ifdef _ABI_SOURCE
  669.             getrlimit (RLIMIT_NOFILE, &rl);
  670.             fd = rl.rlim_max;
  671. #else
  672.             fd = getdtablesize ();
  673. #endif
  674.             while (--fd > 2)
  675.                 (void) close (fd);
  676.             execvp (xargv[0],xargv);
  677.             exit (0);
  678.         }
  679.         listfiles ();
  680.         sendfiles ();
  681.     }
  682.     finishup (starttime);
  683.     if (collname)  free (collname);
  684.     if (basedir)  free (basedir);
  685.     if (prefix)  free (prefix);
  686.     if (release)  free (release);
  687.     if (rcs_branch)  free (rcs_branch);
  688. #ifdef CVS
  689.     if (cvs_root)  free (cvs_root);
  690. #endif
  691.     if (goawayreason) {
  692.         if (donereason == goawayreason)
  693.             donereason = NULL;
  694.         free (goawayreason);
  695.     }
  696.     if (donereason)  free (donereason);
  697.     if (lockfd >= 0)  (void) close (lockfd);
  698.     endpwent ();
  699.     (void) endgrent ();
  700. #if    CMUCS
  701.     endacent ();
  702. #endif    /* CMUCS */
  703.     Hfree (uidH);
  704.     Hfree (gidH);
  705.     Hfree (inodeH);
  706. }
  707.  
  708. /*****************************************
  709.  ***    S I G N   O N   C L I E N T    ***
  710.  *****************************************/
  711.  
  712. signon ()
  713. {
  714.     register int x;
  715.  
  716.     xpatch = FALSE;
  717.     x = msgsignon ();
  718.     if (x != SCMOK)  goaway ("Error reading signon request from client");
  719.     x = msgsignonack ();
  720.     if (x != SCMOK)  goaway ("Error sending signon reply to client");
  721.     free (scmver);
  722.     scmver = NULL;
  723. }
  724.  
  725. /*****************************************************************
  726.  ***    E X C H A N G E   S E T U P   I N F O R M A T I O N    ***
  727.  *****************************************************************/
  728.  
  729. setup ()
  730. {
  731.     register int x;
  732.     char *p,*q;
  733.     char buf[STRINGLENGTH];
  734.     register FILE *f;
  735.     struct stat sbuf;
  736.     register TREELIST *tl;
  737. #ifdef _ABI_SOURCE
  738.     struct flock lock;
  739. #endif
  740.  
  741.     if (protver > 7) {
  742.         cancompress = TRUE;
  743.     }
  744.     x = msgsetup ();
  745.     if (x != SCMOK)  goaway ("Error reading setup request from client");
  746.     if (protver < 4) {
  747.         setupack = FSETUPOLD;
  748.         (void) msgsetupack ();
  749.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  750.         goaway ("Sup client using obsolete version of protocol");
  751.     }
  752.     if (xpatch) {
  753.         register struct passwd *pw;
  754.         extern int link_nofollow(), local_file();
  755.  
  756.         if ((pw = getpwnam (xuser)) == NULL) {
  757.             setupack = FSETUPSAME;
  758.             (void) msgsetupack ();
  759.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  760.             goaway ("User not found");
  761.         }
  762.         (void) free (xuser);
  763.         xuser = salloc (pw->pw_dir);
  764.  
  765.         /* check crosspatch host access file */
  766.         cryptkey = NULL;
  767.         (void) sprintf (buf,FILEXPATCH,xuser);
  768.  
  769.         /* Turn off link following */
  770.         if (link_nofollow(1) != -1) {
  771.             int hostok = FALSE;
  772.             /* get stat info before open */
  773.             if (stat(buf, &sbuf) == -1)
  774.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  775.  
  776.             if ((f = fopen (buf,"r")) != NULL) {
  777.                 struct stat fsbuf;
  778.  
  779.                 while (p = fgets (buf,STRINGLENGTH,f)) {
  780.                     q = index (p,'\n');
  781.                     if (q)  *q = 0;
  782.                     if (index ("#;:",*p))  continue;
  783.                     q = nxtarg (&p," \t");
  784.                     if (*p == '\0')  continue;
  785.                     if (!matchhost(q)) continue;
  786.  
  787.                     cryptkey = salloc (p);
  788.                     hostok = TRUE;
  789.                     if (local_file(fileno(f), &fsbuf) > 0
  790.                         && stat_info_ok(&sbuf, &fsbuf)) {
  791.                         runas_uid = sbuf.st_uid;
  792.                         runas_gid = sbuf.st_gid;
  793.                     }
  794.                     break;
  795.                 }
  796.                 (void) fclose (f);
  797.             }
  798.  
  799.             /* Restore link following */
  800.             if (link_nofollow(0) == -1)
  801.                 goaway ("Restore link following");
  802.  
  803.             if (!hostok) {
  804.                 setupack = FSETUPHOST;
  805.                 (void) msgsetupack ();
  806.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  807.                 goaway ("Host not on access list");
  808.             }
  809.         }
  810.         setupack = FSETUPOK;
  811.         x = msgsetupack ();
  812.         if (x != SCMOK)
  813.             goaway ("Error sending setup reply to client");
  814.         return;
  815.     }
  816. #ifdef RCS
  817.         if (candorcs && release != NULL &&
  818.             (strncmp(release, "RCS.", 4) == 0)) {
  819.                 rcs_branch = salloc(&release[4]);
  820.                 free(release);
  821.                 release = salloc("RCS");
  822.                 dorcs = TRUE;
  823.         }
  824. #endif
  825.     if (release == NULL)
  826.         release = salloc (DEFRELEASE);
  827.     if (basedir == NULL || *basedir == '\0') {
  828.         basedir = NULL;
  829.         (void) sprintf (buf,FILEDIRS,DEFDIR);
  830.         f = fopen (buf,"r");
  831.         if (f) {
  832.             while (p = fgets (buf,STRINGLENGTH,f)) {
  833.                 q = index (p,'\n');
  834.                 if (q)  *q = 0;
  835.                 if (index ("#;:",*p))  continue;
  836.                 q = nxtarg (&p," \t=");
  837.                 if (strcmp(q,collname) == 0) {
  838.                     basedir = skipover(p," \t=");
  839.                     basedir = salloc (basedir);
  840.                     break;
  841.                 }
  842.             }
  843.             (void) fclose (f);
  844.         }
  845.         if (basedir == NULL) {
  846.             (void) sprintf (buf,FILEBASEDEFAULT,collname);
  847.             basedir = salloc(buf);
  848.         }
  849.     }
  850.     if (chdir (basedir) < 0)
  851.         goaway ("Can't chdir to base directory %s",basedir);
  852.     (void) sprintf (buf,FILEPREFIX,collname);
  853.     f = fopen (buf,"r");
  854.     if (f) {
  855.         while (p = fgets (buf,STRINGLENGTH,f)) {
  856.             q = index (p,'\n');
  857.             if (q)  *q = 0;
  858.             if (index ("#;:",*p))  continue;
  859.             prefix = salloc(p);
  860.             if (chdir (prefix) < 0)
  861.                 goaway ("Can't chdir to %s from base directory %s",
  862.                     prefix,basedir);
  863.             break;
  864.         }
  865.         (void) fclose (f);
  866.     }
  867.     x = stat (".",&sbuf);
  868.     if (prefix)  (void) chdir (basedir);
  869.     if (x < 0)
  870.         goaway ("Can't stat base/prefix directory");
  871.     if (nchildren >= maxchildren) {
  872.         setupack = FSETUPBUSY;
  873.         (void) msgsetupack ();
  874.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  875.         goaway ("Sup client told to try again later");
  876.     }
  877.     if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
  878.         setupack = FSETUPSAME;
  879.         (void) msgsetupack ();
  880.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  881.         goaway ("Attempt to upgrade to same directory on same host");
  882.     }
  883.     /* obtain release information */
  884.     if (!getrelease (release)) {
  885.         setupack = FSETUPRELEASE;
  886.         (void) msgsetupack ();
  887.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  888.         goaway ("Invalid release information");
  889.     }
  890.     /* check host access file */
  891.     cryptkey = NULL;
  892.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  893.         char *h;
  894.         if ((h = tl->TLhost) == NULL)
  895.             h = FILEHOSTDEF;
  896.         (void) sprintf (buf,FILEHOST,collname,h);
  897.         f = fopen (buf,"r");
  898.         if (f) {
  899.             int hostok = FALSE;
  900.             while (p = fgets (buf,STRINGLENGTH,f)) {
  901.                 int not;
  902.                 q = index (p,'\n');
  903.                 if (q)  *q = 0;
  904.                 if (index ("#;:",*p))  continue;
  905.                 q = nxtarg (&p," \t");
  906.                 if ((not = (*q == '!')) && *++q == '\0')
  907.                     q = nxtarg (&p," \t");
  908.                 hostok = (not == (matchhost(q) == 0));
  909.                 if (hostok) {
  910.                     while ((*p == ' ') || (*p == '\t')) p++;
  911.                     if (*p)  cryptkey = salloc (p);
  912.                     break;
  913.                 }
  914.             }
  915.             (void) fclose (f);
  916.             if (!hostok) {
  917.                 setupack = FSETUPHOST;
  918.                 (void) msgsetupack ();
  919.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  920.                 goaway ("Host not on access list for %s",
  921.                     collname);
  922.             }
  923.         }
  924.     }
  925.     /* try to lock collection */
  926.     (void) sprintf (buf,FILELOCK,collname);
  927.     x = open (buf,O_RDONLY,0);
  928.     if (x >= 0) {
  929. #ifdef _ABI_SOURCE
  930.         /* lock setup: read lock for whole file */
  931.         lock.l_type = F_RDLCK;
  932.         lock.l_start = 0;
  933.         lock.l_whence = 0;
  934.         lock.l_len = 0;
  935.         if (fcntl (x, F_SETLK, &lock) < 0) {
  936.             (void) close (x);
  937.             if (errno != EACCES)
  938.                 goaway ("Can't lock collection %s",collname);
  939.             setupack = FSETUPBUSY;
  940.             (void) msgsetupack ();
  941.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  942.             goaway ("Sup client told to wait for lock");
  943.         }
  944.         lockfd = x;
  945. #else
  946.         if (flock (x,(LOCK_SH|LOCK_NB)) < 0) {
  947.             (void) close (x);
  948.             if (errno != EWOULDBLOCK)
  949.                 goaway ("Can't lock collection %s",collname);
  950.             setupack = FSETUPBUSY;
  951.             (void) msgsetupack ();
  952.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  953.             goaway ("Sup client told to wait for lock");
  954.         }
  955.         lockfd = x;
  956. #endif
  957.     }
  958.     setupack = FSETUPOK;
  959.     x = msgsetupack ();
  960.     if (x != SCMOK)  goaway ("Error sending setup reply to client");
  961. }
  962.  
  963. /** Test data encryption **/
  964. docrypt ()
  965. {
  966.     register int x;
  967.     char *p,*q;
  968.     char buf[STRINGLENGTH];
  969.     register FILE *f;
  970.     struct stat sbuf;
  971.     extern int  link_nofollow(), local_file();
  972.  
  973.     if (!xpatch) {
  974.         (void) sprintf (buf,FILECRYPT,collname);
  975.  
  976.         /* Turn off link following */
  977.         if (link_nofollow(1) != -1) {
  978.             /* get stat info before open */
  979.             if (stat(buf, &sbuf) == -1)
  980.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  981.  
  982.             if ((f = fopen (buf,"r")) != NULL) {
  983.                 struct stat fsbuf;
  984.  
  985.                 if (cryptkey == NULL &&
  986.                     (p = fgets (buf,STRINGLENGTH,f))) {
  987.                     if (q = index (p,'\n'))  *q = '\0';
  988.                     if (*p)  cryptkey = salloc (buf);
  989.                 }
  990.                 if (local_file(fileno(f), &fsbuf) > 0
  991.                     && stat_info_ok(&sbuf, &fsbuf)) {
  992.                     runas_uid = sbuf.st_uid;
  993.                     runas_gid = sbuf.st_gid;
  994.                 }
  995.                 (void) fclose (f);
  996.             }
  997.             /* Restore link following */
  998.             if (link_nofollow(0) == -1)
  999.                 goaway ("Restore link following");
  1000.         }
  1001.     }
  1002.     if ( netcrypt (cryptkey) != SCMOK )
  1003.         goaway ("Runing non-crypting supfilesrv");
  1004.     x = msgcrypt ();
  1005.     if (x != SCMOK)
  1006.         goaway ("Error reading encryption test request from client");
  1007.     (void) netcrypt ((char *)NULL);
  1008.     if (strcmp(crypttest,CRYPTTEST) != 0)
  1009.         goaway ("Client not encrypting data properly");
  1010.     free (crypttest);
  1011.     crypttest = NULL;
  1012.     x = msgcryptok ();
  1013.     if (x != SCMOK)
  1014.         goaway ("Error sending encryption test reply to client");
  1015. }
  1016.  
  1017. /***************************************************************
  1018.  ***    C O N N E C T   T O   P R O P E R   A C C O U N T    ***
  1019.  ***************************************************************/
  1020.  
  1021. login ()
  1022. {
  1023.     char *changeuid ();
  1024.     register int x,fileuid,filegid;
  1025.  
  1026.     (void) netcrypt (PSWDCRYPT);    /* encrypt acct name and password */
  1027.     x = msglogin ();
  1028.     (void) netcrypt ((char *)NULL); /* turn off encryption */
  1029.     if (x != SCMOK)  goaway ("Error reading login request from client");
  1030.     if ( logcrypt ) {
  1031.         if (strcmp(logcrypt,CRYPTTEST) != 0) {
  1032.         logack = FLOGNG;
  1033.         logerror = "Improper login encryption";
  1034.         (void) msglogack ();
  1035.         goaway ("Client not encrypting login information properly");
  1036.         }
  1037.         free (logcrypt);
  1038.         logcrypt = NULL;
  1039.     }
  1040.     if (loguser == NULL) {
  1041.         if (cryptkey) {
  1042.             if (runas_uid >= 0 && runas_gid >= 0) {
  1043.                 fileuid = runas_uid;
  1044.                 filegid = runas_gid;
  1045.                 loguser = NULL;
  1046.             } else
  1047.                 loguser = salloc (DEFUSER);
  1048.         } else
  1049.             loguser = salloc (DEFUSER);
  1050.     }
  1051.     if ((logerror = changeuid (loguser,logpswd,fileuid,filegid)) != NULL) {
  1052.         logack = FLOGNG;
  1053.         (void) msglogack ();
  1054.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  1055.         goaway ("Client denied login access");
  1056.     }
  1057.     if (loguser)  free (loguser);
  1058.     if (logpswd)  free (logpswd);
  1059.     logack = FLOGOK;
  1060.     x = msglogack ();
  1061.     if (x != SCMOK)  goaway ("Error sending login reply to client");
  1062.     if (!xpatch)  /* restore desired encryption */
  1063.         if (netcrypt (cryptkey) != SCMOK)
  1064.             goaway("Running non-crypting supfilesrv");
  1065.     free (cryptkey);
  1066.     cryptkey = NULL;
  1067. }
  1068.  
  1069. /*****************************************
  1070.  ***    M A K E   N A M E   L I S T    ***
  1071.  *****************************************/
  1072.  
  1073. listfiles ()
  1074. {
  1075.     int denyone();
  1076.     register int x;
  1077.  
  1078.     refuseT = NULL;
  1079.     x = msgrefuse ();
  1080.     if (x != SCMOK)  goaway ("Error reading refuse list from client");
  1081.     getscanlists ();
  1082.     Tfree (&refuseT);
  1083.     x = msglist ();
  1084.     if (x != SCMOK)  goaway ("Error sending file list to client");
  1085.     Tfree (&listT);
  1086.     listT = NULL;
  1087.     needT = NULL;
  1088.     x = msgneed ();
  1089.     if (x != SCMOK)
  1090.         goaway ("Error reading needed files list from client");
  1091.     denyT = NULL;
  1092.     (void) Tprocess (needT,denyone);
  1093.     Tfree (&needT);
  1094.     x = msgdeny ();
  1095.     if (x != SCMOK)  goaway ("Error sending denied files list to client");
  1096.     Tfree (&denyT);
  1097. }
  1098.  
  1099. denyone (t)
  1100. register TREE *t;
  1101. {
  1102.     register TREELIST *tl;
  1103.     register char *name = t->Tname;
  1104.     register int update = (t->Tflags&FUPDATE) != 0;
  1105.     struct stat sbuf;
  1106.     register TREE *tlink;
  1107.     TREE *linkcheck ();
  1108.     char slinkname[STRINGLENGTH];
  1109.     register int x;
  1110.  
  1111.     for (tl = listTL; tl != NULL; tl = tl->TLnext)
  1112.         if ((t = Tsearch (tl->TLtree,name)) != NULL)
  1113.             break;
  1114.     if (t == NULL) {
  1115.         (void) Tinsert (&denyT,name,FALSE);
  1116.         return (SCMOK);
  1117.     }
  1118.     cdprefix (tl->TLprefix);
  1119.     if ((t->Tmode&S_IFMT) == S_IFLNK)
  1120.         x = lstat(name,&sbuf);
  1121.     else
  1122.         x = stat(name,&sbuf);
  1123.     if (x < 0 || (sbuf.st_mode&S_IFMT) != (t->Tmode&S_IFMT)) {
  1124.         (void) Tinsert (&denyT,name,FALSE);
  1125.         return (SCMOK);
  1126.     }
  1127.     switch (t->Tmode&S_IFMT) {
  1128.     case S_IFLNK:
  1129.         if ((x = readlink (name,slinkname,STRINGLENGTH)) <= 0) {
  1130.             (void) Tinsert (&denyT,name,FALSE);
  1131.             return (SCMOK);
  1132.         }
  1133.         slinkname[x] = '\0';
  1134.         (void) Tinsert (&t->Tlink,slinkname,FALSE);
  1135.         break;
  1136.     case S_IFREG:
  1137.         if (sbuf.st_nlink > 1 &&
  1138.             (tlink = linkcheck (t,(int)sbuf.st_dev,(int)sbuf.st_ino)))
  1139.         {
  1140.             (void) Tinsert (&tlink->Tlink,name,FALSE);
  1141.             return (SCMOK);
  1142.         }
  1143.         if (update)  t->Tflags |= FUPDATE;
  1144.     case S_IFDIR:
  1145.         t->Tuid = sbuf.st_uid;
  1146.         t->Tgid = sbuf.st_gid;
  1147.         break;
  1148.     default:
  1149.         (void) Tinsert (&denyT,name,FALSE);
  1150.         return (SCMOK);
  1151.     }
  1152.     t->Tflags |= FNEEDED;
  1153.     return (SCMOK);
  1154. }
  1155.  
  1156. /*********************************
  1157.  ***    S E N D   F I L E S    ***
  1158.  *********************************/
  1159.  
  1160. sendfiles ()
  1161. {
  1162.     int sendone(),senddir(),sendfile();
  1163.     register TREELIST *tl;
  1164.     register int x;
  1165.  
  1166.     /* Does the protocol support compression */
  1167.     if (cancompress) {
  1168.         /* Check for compression on sending files */
  1169.         x = msgcompress();
  1170.         if ( x != SCMOK)
  1171.             goaway ("Error sending compression check to server");
  1172.     }
  1173.     /* send all files */
  1174.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1175.         cdprefix (tl->TLprefix);
  1176. #ifdef CVS
  1177.                 if (candorcs) {
  1178.                         cvs_root = getcwd(NULL, 256);
  1179.                         if (access("CVSROOT", F_OK) < 0)
  1180.                                 dorcs = FALSE;
  1181.                         else {
  1182.                                 loginfo("is a CVSROOT \"%s\"\n", cvs_root);
  1183.                                 dorcs = TRUE;
  1184.                         }
  1185.                 }
  1186. #endif
  1187.         (void) Tprocess (tl->TLtree,sendone);
  1188.     }
  1189.     /* send directories in reverse order */
  1190.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1191.         cdprefix (tl->TLprefix);
  1192.         (void) Trprocess (tl->TLtree,senddir);
  1193.     }
  1194.     x = msgsend ();
  1195.     if (x != SCMOK)
  1196.         goaway ("Error reading receive file request from client");
  1197.     upgradeT = NULL;
  1198.     x = msgrecv (sendfile,0);
  1199.     if (x != SCMOK)
  1200.         goaway ("Error sending file to client");
  1201. }
  1202.  
  1203. sendone (t)
  1204. TREE *t;
  1205. {
  1206.     register int x,fd;
  1207.     register int fdtmp;
  1208.     char sys_com[STRINGLENGTH], temp_file[STRINGLENGTH], rcs_file[STRINGLENGTH];
  1209.         union wait status;
  1210.     char *uconvert(),*gconvert();
  1211.     int sendfile ();
  1212.  
  1213.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1214.         return (SCMOK);
  1215.     if ((t->Tmode&S_IFMT) == S_IFDIR) /* send no directories this pass */
  1216.         return (SCMOK);
  1217.     x = msgsend ();
  1218.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1219.     upgradeT = t;            /* upgrade file pointer */
  1220.     fd = -1;            /* no open file */
  1221.     if ((t->Tmode&S_IFMT) == S_IFREG) {
  1222.         if (!listonly && (t->Tflags&FUPDATE) == 0) {
  1223. #ifdef RCS
  1224.                         if (dorcs) {
  1225.                                 char rcs_release[STRINGLENGTH];
  1226.  
  1227.                 tmpnam(rcs_file);
  1228.                                 if (strcmp(&t->Tname[strlen(t->Tname)-2], ",v") == 0) {
  1229.                                         t->Tname[strlen(t->Tname)-2] = '\0';
  1230.                                         if (rcs_branch != NULL)
  1231. #ifdef CVS
  1232.                                                 sprintf(rcs_release, "-r %s", rcs_branch);
  1233. #else
  1234.                                                 sprintf(rcs_release, "-r%s", rcs_branch);
  1235. #endif
  1236.                                         else
  1237.                                                 rcs_release[0] = '\0';
  1238. #ifdef CVS
  1239.                                         sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, t->Tname, rcs_file);
  1240. #else
  1241.                                         sprintf(sys_com, "co -q -p %s %s > %s 2> /dev/null\n", rcs_release, t->Tname, rcs_file);
  1242. #endif
  1243.                                         /*loginfo("using rcs mode \"%s\"\n", sys_com);*/
  1244.                                         status.w_status = system(sys_com);
  1245.                                         if (status.w_status < 0 || status.w_retcode) {
  1246.                                                 /* Just in case */
  1247.                                                 unlink(rcs_file);
  1248.                                                 if (status.w_status < 0) {
  1249.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1250.                                                         t->Tmode = 0;
  1251.                                                 }
  1252.                                                 else {
  1253.                                                         /*logerr("rcs command failed \"%s\" = %d\n",
  1254.                                                                sys_com, status.w_retcode);*/
  1255.                                                         t->Tflags |= FUPDATE;
  1256.                                                 }
  1257.                                         }
  1258.                                         else if (docompress) {
  1259.                                                 tmpnam(temp_file);
  1260.                                                 sprintf(sys_com, "gzip -c < %s > %s\n", rcs_file, temp_file);
  1261.                                                 if (system(sys_com) < 0) {
  1262.                                                         /* Just in case */
  1263.                                                         unlink(temp_file);
  1264.                                                         unlink(rcs_file);
  1265.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1266.                                                         t->Tmode = 0;
  1267.                                                 }
  1268.                                                 fd = open (temp_file,O_RDONLY,0);
  1269.                                         }
  1270.                                         else
  1271.                                                 fd = open (rcs_file,O_RDONLY,0);
  1272.                                 }
  1273.                         }
  1274. #endif
  1275.                         if (fd == -1) {
  1276.                                 if (docompress) {
  1277.                                         tmpnam(temp_file);
  1278.                                         sprintf(sys_com, "gzip -c < %s > %s\n", t->Tname, temp_file);
  1279.                                         if (system(sys_com) < 0) {
  1280.                                                 /* Just in case */
  1281.                                                 unlink(temp_file);
  1282.                                                 goaway ("We died trying to \"%s\"", sys_com);
  1283.                                                 t->Tmode = 0;
  1284.                                         }
  1285.                                         fd = open (temp_file,O_RDONLY,0);
  1286.                                 }
  1287.                                 else
  1288.                                         fd = open (t->Tname,O_RDONLY,0);
  1289.                         }
  1290.             if (fd < 0 && (t->Tflags&FUPDATE) == 0)  t->Tmode = 0;
  1291.         }
  1292.         if (t->Tmode) {
  1293.             t->Tuser = salloc (uconvert (t->Tuid));
  1294.             t->Tgroup = salloc (gconvert (t->Tgid));
  1295.         }
  1296.     }
  1297.     x = msgrecv (sendfile,fd);
  1298.     if (docompress)
  1299.         unlink(temp_file);
  1300. #ifdef RCS
  1301.     if (dorcs)
  1302.         unlink(rcs_file);
  1303. #endif
  1304.     if (x != SCMOK)  goaway ("Error sending file to client");
  1305.     return (SCMOK);
  1306. }
  1307.  
  1308. senddir (t)
  1309. TREE *t;
  1310. {
  1311.     register int x;
  1312.     char *uconvert(),*gconvert();
  1313.     int sendfile ();
  1314.  
  1315.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1316.         return (SCMOK);
  1317.     if ((t->Tmode&S_IFMT) != S_IFDIR) /* send only directories this pass */
  1318.         return (SCMOK);
  1319.     x = msgsend ();
  1320.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1321.     upgradeT = t;            /* upgrade file pointer */
  1322.     t->Tuser = salloc (uconvert (t->Tuid));
  1323.     t->Tgroup = salloc (gconvert (t->Tgid));
  1324.     x = msgrecv (sendfile,0);
  1325.     if (x != SCMOK)  goaway ("Error sending file to client");
  1326.     return (SCMOK);
  1327. }
  1328.  
  1329. sendfile (t,ap)
  1330. register TREE *t;
  1331. va_list ap;
  1332. {
  1333.     register int x;
  1334.     int fd = va_arg(ap,int);
  1335.     if ((t->Tmode&S_IFMT) != S_IFREG || listonly || (t->Tflags&FUPDATE))
  1336.         return (SCMOK);
  1337.     x = writefile (fd);
  1338.     if (x != SCMOK)  goaway ("Error sending file to client");
  1339.         (void) close (fd);
  1340.     return (SCMOK);
  1341. }
  1342.  
  1343. /*****************************************
  1344.  ***    E N D   C O N N E C T I O N    ***
  1345.  *****************************************/
  1346.  
  1347. finishup (starttime)
  1348. long starttime;
  1349. {
  1350.     register int x = SCMOK;
  1351.     char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
  1352.     int logfd;
  1353.     struct stat sbuf;
  1354.     long finishtime;
  1355.     char *releasename;
  1356.  
  1357.     (void) netcrypt ((char *)NULL);
  1358.     if (protver < 6) {
  1359.         if (goawayreason != NULL)
  1360.             free (goawayreason);
  1361.         goawayreason = (char *)NULL;
  1362.         x = msggoaway();
  1363.         doneack = FDONESUCCESS;
  1364.         donereason = salloc ("Unknown");
  1365.     } else if (goawayreason == (char *)NULL)
  1366.         x = msgdone ();
  1367.     else {
  1368.         doneack = FDONEGOAWAY;
  1369.         donereason = goawayreason;
  1370.     }
  1371.     if (x == SCMEOF || x == SCMERR) {
  1372.         doneack = FDONEUSRERROR;
  1373.         donereason = salloc ("Premature EOF on network");
  1374.     } else if (x != SCMOK) {
  1375.         doneack = FDONESRVERROR;
  1376.         donereason = salloc ("Unknown SCM code");
  1377.     }
  1378.     if (doneack == FDONEDONTLOG)
  1379.         return;
  1380.     if (donereason == NULL)
  1381.         donereason = salloc ("No reason");
  1382.     if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
  1383.         logerr ("%s", donereason);
  1384.     else if (doneack == FDONEGOAWAY)
  1385.         logerr ("GOAWAY: %s",donereason);
  1386.     else if (doneack != FDONESUCCESS)
  1387.         logerr ("Reason %d:  %s",doneack,donereason);
  1388.     goawayreason = donereason;
  1389.     cdprefix ((char *)NULL);
  1390.     (void) sprintf (lognam,FILELOGFILE,collname);
  1391.     if ((logfd = open(lognam,O_APPEND|O_WRONLY,0644)) < 0)
  1392.         return; /* can not open file up...error */
  1393.     finishtime = time ((long *)NULL);
  1394.     p = tmpbuf;
  1395.     (void) sprintf (p,"%s ",fmttime (lasttime));
  1396.     p += strlen(p);
  1397.     (void) sprintf (p,"%s ",fmttime (starttime));
  1398.     p += strlen(p);
  1399.     (void) sprintf (p,"%s ",fmttime (finishtime));
  1400.     p += strlen(p);
  1401.     if ((releasename = release) == NULL)
  1402.         releasename = "UNKNOWN";
  1403.     (void) sprintf (p,"%s %s %d %s\n",remotehost(),releasename,
  1404.         FDONESUCCESS-doneack,donereason);
  1405.     p += strlen(p);
  1406. #if    MACH
  1407.     /* if we are busy dont get stuck updating the disk if full */
  1408.     if(setupack == FSETUPBUSY) {
  1409.         long l = FIOCNOSPC_ERROR;
  1410.         ioctl(logfd, FIOCNOSPC, &l);
  1411.     }
  1412. #endif    /* MACH */
  1413.     (void) write(logfd,tmpbuf,(p - tmpbuf));
  1414.     (void) close(logfd);
  1415. }
  1416.  
  1417. /***************************************************
  1418.  ***    H A S H   T A B L E   R O U T I N E S    ***
  1419.  ***************************************************/
  1420.  
  1421. Hfree (table)
  1422. HASH **table;
  1423. {
  1424.     register HASH *h;
  1425.     register int i;
  1426.     for (i = 0; i < HASHSIZE; i++)
  1427.         while (h = table[i]) {
  1428.             table[i] = h->Hnext;
  1429.             if (h->Hname)  free (h->Hname);
  1430.             free ((char *)h);
  1431.         }
  1432. }
  1433.  
  1434. HASH *Hlookup (table,num1,num2)
  1435. HASH **table;
  1436. int num1,num2;
  1437. {
  1438.     register HASH *h;
  1439.     register int hno;
  1440.     hno = HASHFUNC(num1,num2);
  1441.     for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
  1442.     return (h);
  1443. }
  1444.  
  1445. Hinsert (table,num1,num2,name,tree)
  1446. HASH **table;
  1447. int num1,num2;
  1448. char *name;
  1449. TREE *tree;
  1450. {
  1451.     register HASH *h;
  1452.     register int hno;
  1453.     hno = HASHFUNC(num1,num2);
  1454.     h = (HASH *) malloc (sizeof(HASH));
  1455.     h->Hnum1 = num1;
  1456.     h->Hnum2 = num2;
  1457.     h->Hname = name;
  1458.     h->Htree = tree;
  1459.     h->Hnext = table[hno];
  1460.     table[hno] = h;
  1461. }
  1462.  
  1463. /*********************************************
  1464.  ***    U T I L I T Y   R O U T I N E S    ***
  1465.  *********************************************/
  1466.  
  1467. TREE *linkcheck (t,d,i)
  1468. TREE *t;
  1469. int d,i;            /* inode # and device # */
  1470. {
  1471.     register HASH *h;
  1472.     h = Hlookup (inodeH,i,d);
  1473.     if (h)  return (h->Htree);
  1474.     Hinsert (inodeH,i,d,(char *)NULL,t);
  1475.     return ((TREE *)NULL);
  1476. }
  1477.  
  1478. char *uconvert (uid)
  1479. int uid;
  1480. {
  1481.     register struct passwd *pw;
  1482.     register char *p;
  1483.     register HASH *u;
  1484.     u = Hlookup (uidH,uid,0);
  1485.     if (u)  return (u->Hname);
  1486.     pw = getpwuid (uid);
  1487.     if (pw == NULL)  return ("");
  1488.     p = salloc (pw->pw_name);
  1489.     Hinsert (uidH,uid,0,p,(TREE*)NULL);
  1490.     return (p);
  1491. }
  1492.  
  1493. char *gconvert (gid)
  1494. int gid;
  1495. {
  1496.     register struct group *gr;
  1497.     register char *p;
  1498.     register HASH *g;
  1499.     g = Hlookup (gidH,gid,0);
  1500.     if (g)  return (g->Hname);
  1501.     gr = getgrgid (gid);
  1502.     if (gr == NULL)  return ("");
  1503.     p = salloc (gr->gr_name);
  1504.     Hinsert (gidH,gid,0,p,(TREE *)NULL);
  1505.     return (p);
  1506. }
  1507.  
  1508. char *changeuid (namep,passwordp,fileuid,filegid)
  1509. char *namep,*passwordp;
  1510. int fileuid,filegid;
  1511. {
  1512.     char *okpassword ();
  1513.     char *group,*account,*pswdp;
  1514.     struct passwd *pwd;
  1515.     struct group *grp;
  1516. #if    CMUCS
  1517.     struct account *acc;
  1518.     struct ttyloc tlc;
  1519. #endif    /* CMUCS */
  1520.     register int status = ACCESS_CODE_OK;
  1521.     char nbuf[STRINGLENGTH];
  1522.     static char errbuf[STRINGLENGTH];
  1523. #if    CMUCS
  1524.     int *grps;
  1525. #endif    /* CMUCS */
  1526.     char *p;
  1527.  
  1528.     if (namep == NULL) {
  1529.         pwd = getpwuid (fileuid);
  1530.         if (pwd == NULL) {
  1531.             (void) sprintf (errbuf,"Reason:  Unknown user id %d",
  1532.                 fileuid);
  1533.             return (errbuf);
  1534.         }
  1535.         grp = getgrgid (filegid);
  1536.         if (grp)  group = strcpy (nbuf,grp->gr_name);
  1537.         else  group = NULL;
  1538.         account = NULL;
  1539.         pswdp = NULL;
  1540.     } else {
  1541.         (void) strcpy (nbuf,namep);
  1542.         account = group = index (nbuf,',');
  1543.         if (group != NULL) {
  1544.             *group++ = '\0';
  1545.             account = index (group,',');
  1546.             if (account != NULL) {
  1547.                 *account++ = '\0';
  1548.                 if (*account == '\0')  account = NULL;
  1549.             }
  1550.             if (*group == '\0')  group = NULL;
  1551.         }
  1552.         pwd = getpwnam (nbuf);
  1553.         if (pwd == NULL) {
  1554.             (void) sprintf (errbuf,"Reason:  Unknown user %s",
  1555.                 nbuf);
  1556.             return (errbuf);
  1557.         }
  1558.         if (strcmp (nbuf,DEFUSER) == 0)
  1559.             pswdp = NULL;
  1560.         else
  1561.             pswdp = passwordp ? passwordp : "";
  1562. #ifdef AFS
  1563.                 if (strcmp (nbuf,DEFUSER) != 0) {
  1564.                         char *reason;
  1565.                         setpag(); /* set a pag */
  1566.                         if (ka_UserAuthenticate(pwd->pw_name, "", 0,
  1567.                                                 pswdp, 1, &reason)) {
  1568.                                 (void) sprintf (errbuf,"AFS authentication failed, %s",
  1569.                                                 reason);
  1570.                                 logerr ("Attempt by %s; %s",
  1571.                                         nbuf, errbuf);
  1572.                                 return (errbuf);
  1573.                         }
  1574.                 }
  1575. #endif
  1576.     }
  1577.     if (getuid () != 0) {
  1578.         if (getuid () == pwd->pw_uid)
  1579.             return (NULL);
  1580.         if (strcmp (pwd->pw_name,DEFUSER) == 0)
  1581.             return (NULL);
  1582.         logerr ("Fileserver not superuser");
  1583.         return ("Reason:  fileserver is not running privileged");
  1584.     }
  1585. #if    CMUCS
  1586.     tlc.tlc_hostid = TLC_UNKHOST;
  1587.     tlc.tlc_ttyid = TLC_UNKTTY;
  1588.     if (okaccess(pwd->pw_name,ACCESS_TYPE_SU,0,-1,tlc) != 1)
  1589.         status = ACCESS_CODE_DENIED;
  1590.     else {
  1591.         grp = NULL;
  1592.         acc = NULL;
  1593.         status = oklogin(pwd->pw_name,group,&account,pswdp,&pwd,&grp,&acc,&grps);
  1594.         if (status == ACCESS_CODE_OK) {
  1595.             if ((p = okpassword(pswdp,pwd->pw_name,pwd->pw_gecos)) != NULL)
  1596.                 status = ACCESS_CODE_INSECUREPWD;
  1597.         }
  1598.     }
  1599. #else    /* CMUCS */
  1600.     status = ACCESS_CODE_OK;
  1601.     if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
  1602.         if (strcmp(pwd->pw_passwd,(char *)crypt(pswdp,pwd->pw_passwd)))
  1603.             status = ACCESS_CODE_BADPASSWORD;
  1604. #endif    /* CMUCS */
  1605.     switch (status) {
  1606.     case ACCESS_CODE_OK:
  1607.         break;
  1608.     case ACCESS_CODE_BADPASSWORD:
  1609.         p = "Reason:  Invalid password";
  1610.         break;
  1611. #if    CMUCS
  1612.     case ACCESS_CODE_INSECUREPWD:
  1613.         (void) sprintf (errbuf,"Reason:  %s",p);
  1614.         p = errbuf;
  1615.         break;
  1616.     case ACCESS_CODE_DENIED:
  1617.         p = "Reason:  Access denied";
  1618.         break;
  1619.     case ACCESS_CODE_NOUSER:
  1620.         p = errbuf;
  1621.         break;
  1622.     case ACCESS_CODE_ACCEXPIRED:
  1623.         p = "Reason:  Account expired";
  1624.         break;
  1625.     case ACCESS_CODE_GRPEXPIRED:
  1626.         p = "Reason:  Group expired";
  1627.         break;
  1628.     case ACCESS_CODE_ACCNOTVALID:
  1629.         p = "Reason:  Invalid account";
  1630.         break;
  1631.     case ACCESS_CODE_MANYDEFACC:
  1632.         p = "Reason:  User has more than one default account";
  1633.         break;
  1634.     case ACCESS_CODE_NOACCFORGRP:
  1635.         p = "Reason:  No account for group";
  1636.         break;
  1637.     case ACCESS_CODE_NOGRPFORACC:
  1638.         p = "Reason:  No group for account";
  1639.         break;
  1640.     case ACCESS_CODE_NOGRPDEFACC:
  1641.         p = "Reason:  No group for default account";
  1642.         break;
  1643.     case ACCESS_CODE_NOTGRPMEMB:
  1644.         p = "Reason:  Not member of group";
  1645.         break;
  1646.     case ACCESS_CODE_NOTDEFMEMB:
  1647.         p = "Reason:  Not member of default group";
  1648.         break;
  1649.     case ACCESS_CODE_OOPS:
  1650.         p = "Reason:  Internal error";
  1651.         break;
  1652. #endif    /* CMUCS */
  1653.     default:
  1654.         (void) sprintf (p = errbuf,"Reason:  Status %d",status);
  1655.         break;
  1656.     }
  1657.     if (pwd == NULL)
  1658.         return (p);
  1659.     if (status != ACCESS_CODE_OK) {
  1660.         logerr ("Login failure for %s",pwd->pw_name);
  1661.         logerr ("%s",p);
  1662. #if    CMUCS
  1663.         logaccess (pwd->pw_name,ACCESS_TYPE_SUP,status,0,-1,tlc);
  1664. #endif    /* CMUCS */
  1665.         return (p);
  1666.     }
  1667. #if    CMUCS
  1668.     if (setgroups (grps[0], &grps[1]) < 0)
  1669.         logerr ("setgroups: %%m");
  1670.     if (setgid ((gid_t)grp->gr_gid) < 0)
  1671.         logerr ("setgid: %%m");
  1672.     if (setuid ((uid_t)pwd->pw_uid) < 0)
  1673.         logerr ("setuid: %%m");
  1674. #else   /* CMUCS */
  1675.     if (initgroups (pwd->pw_name,pwd->pw_gid) < 0)
  1676.         return("Error setting group list");
  1677.     if (setgid (pwd->pw_gid) < 0)
  1678.         logerr ("setgid: %%m");
  1679.     if (setuid (pwd->pw_uid) < 0)
  1680.         logerr ("setuid: %%m");
  1681. #endif    /* CMUCS */
  1682.     return (NULL);
  1683. }
  1684.  
  1685. #if __STDC__
  1686. void
  1687. goaway (char *fmt,...)
  1688. #else
  1689. /*VARARGS*//*ARGSUSED*/
  1690. goaway (va_alist)
  1691. va_dcl
  1692. #endif
  1693. {
  1694. #if !__STDC__
  1695.     register char *fmt;
  1696. #endif
  1697.     char buf[STRINGLENGTH];
  1698.     va_list ap;
  1699.  
  1700.     (void) netcrypt ((char *)NULL);
  1701. #if __STDC__
  1702.     va_start(ap,fmt);
  1703. #else
  1704.     va_start(ap);
  1705.     fmt = va_arg(ap,char *);
  1706. #endif
  1707.     vsnprintf(buf, sizeof(buf), fmt, ap);
  1708.     va_end(ap);
  1709.     goawayreason = salloc (buf);
  1710.     (void) msggoaway ();
  1711.     logerr ("%s",buf);
  1712.     longjmp (sjbuf,TRUE);
  1713. }
  1714.  
  1715. char *fmttime (time)
  1716. long time;
  1717. {
  1718.     static char buf[STRINGLENGTH];
  1719.     int len;
  1720.  
  1721.     (void) strcpy (buf,ctime (&time));
  1722.     len = strlen(buf+4)-6;
  1723.     (void) strncpy (buf,buf+4,len);
  1724.     buf[len] = '\0';
  1725.     return (buf);
  1726. }
  1727.  
  1728. /*
  1729.  * Determine whether the file referenced by the file descriptor 'handle' can
  1730.  * be trusted, namely is it a file resident in the local file system.
  1731.  *
  1732.  * The main method of operation is to perform operations on the file
  1733.  * descriptor so that an attempt to spoof the checks should fail, for
  1734.  * example renamimg the file from underneath us and/or changing where the
  1735.  * file lives from underneath us.
  1736.  *
  1737.  * returns: -1 for error, indicating that we can not tell
  1738.  *         0 for file is definately not local, or it is an RFS link
  1739.  *         1 for file is local and can be trusted
  1740.  *
  1741.  * Side effect: copies the stat information into the supplied buffer,
  1742.  * regardless of the type of file system the file resides.
  1743.  *
  1744.  * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
  1745.  * UFS, where the latter is considered a trusted file.  We assume that the
  1746.  * caller has disabled link following and will detect an attempt to access
  1747.  * a file through an RFS link, except in the case the the last component is
  1748.  * an RFS link.  With link following disabled, the last component itself is
  1749.  * interpreted as a regular file if it is really an RFS link, so we
  1750.  * disallow the RFS link identified by group "symlink" and mode "IEXEC by
  1751.  * owner only". An AFS file is
  1752.  * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
  1753.  * ioctls which operate on a file descriptor.  Note, this AFS ioctl is
  1754.  * implemented in the cache manager, so the decision does not involve a
  1755.  * query with the AFS file server.  An NFS file is detected by looking at
  1756.  * the major device number and seeing if it matches the known values for
  1757.  * MACH NSF/Sun OS 3.x or Sun OS 4.x.
  1758.  *
  1759.  * Having the fstatfs() system call would make this routine easier and
  1760.  * more reliable.
  1761.  *
  1762.  * Note, in order to make the checks simpler, the file referenced by the
  1763.  * file descriptor can not be a BSD style symlink.  Even with symlink
  1764.  * following of the last path component disabled, the attempt to open a
  1765.  * file which is a symlink will succeed, so we check for the BSD symlink
  1766.  * file type here.  Also, the link following on/off and RFS file types
  1767.  * are only relevant in a MACH environment. 
  1768.  */
  1769. #ifdef    AFS
  1770. #include <sys/viceioctl.h>
  1771. #endif
  1772.  
  1773. #define SYMLINK_GRP 64
  1774.  
  1775. int local_file(handle, sinfo)
  1776. int handle;
  1777. struct stat *sinfo;
  1778. {
  1779.     struct stat sb;
  1780. #ifdef    VIOCIGETCELL
  1781.     /*
  1782.      * dummies for the AFS ioctl
  1783.      */
  1784.     struct ViceIoctl vdata;
  1785.     char cellname[512];
  1786. #endif    /* VIOCIGETCELL */
  1787.  
  1788.     if (fstat(handle, &sb) < 0)
  1789.         return(-1);
  1790.     if (sinfo != NULL)
  1791.         *sinfo = sb;
  1792.  
  1793. #if    CMUCS
  1794.     /*
  1795.      * If the following test succeeds, then the file referenced by
  1796.      * 'handle' is actually an RFS link, so we will not trust it.
  1797.      * See <sys/inode.h>.
  1798.      */
  1799.     if (sb.st_gid == SYMLINK_GRP
  1800.         && (sb.st_mode & (S_IFMT|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
  1801.             == (S_IFREG|S_IEXEC))
  1802.         return(0);
  1803. #endif    /* CMUCS */
  1804.  
  1805.     /*
  1806.      * Do not trust BSD style symlinks either.
  1807.      */
  1808.     if ((sb.st_mode & S_IFMT) == S_IFLNK)
  1809.         return(0);
  1810.  
  1811. #ifdef    VIOCIGETCELL
  1812.     /*
  1813.      * This is the VIOCIGETCELL ioctl, which takes an fd, not
  1814.      * a path name.  If it succeeds, then the file is in AFS.
  1815.      *
  1816.      * On failure, ENOTTY indicates that the file was not in
  1817.      * AFS; all other errors are pessimistically assumed to be
  1818.      * a temporary AFS error.
  1819.      */
  1820.     vdata.in_size = 0;
  1821.     vdata.out_size = sizeof(cellname);
  1822.     vdata.out = cellname;
  1823.     if (ioctl(handle, VIOCIGETCELL, (char *)&vdata) != -1)
  1824.         return(0);
  1825.     if (errno != ENOTTY)
  1826.         return(-1);
  1827. #endif    /* VIOCIGETCELL */
  1828.  
  1829.     /*
  1830.      * Verify the file is not in NFS.
  1831.      *
  1832.      * Our current implementation and Sun OS 3.x use major device
  1833.      * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
  1834.      * determined this empirically -- DLC).  Without a fstatfs()
  1835.      * system call, this will have to do for now.
  1836.      */
  1837.     if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
  1838.         return(0);
  1839.  
  1840.     return(1);
  1841. }
  1842.  
  1843. /*
  1844.  * Companion routine for ensuring that a local file can be trusted.  Compare
  1845.  * various pieces of the stat information to make sure that the file can be
  1846.  * trusted.  Returns true for stat information which meets the criteria
  1847.  * for being trustworthy.  The main paranoia is to prevent a hard link to
  1848.  * a root owned file.  Since the link could be removed after the file is
  1849.  * opened, a simply fstat() can not be relied upon.  The two stat buffers
  1850.  * for comparison should come from a stat() on the file name and a following
  1851.  * fstat() on the open file.  Some of the following checks are also an
  1852.  * additional level of paranoia.  Also, this test will fail (correctly) if
  1853.  * either or both of the stat structures have all fields zeroed; typically
  1854.  * due to a stat() failure.
  1855.  */
  1856.  
  1857.  
  1858. int stat_info_ok(sb1, sb2)
  1859. struct stat *sb1, *sb2;
  1860. {
  1861.     return (sb1->st_ino == sb2->st_ino &&    /* Still the same file */
  1862.         sb1->st_dev == sb2->st_dev &&    /* On the same device */
  1863.         sb1->st_mode == sb2->st_mode &&     /* Perms (and type) same */
  1864.         (sb1->st_mode & S_IFMT) == S_IFREG && /* Only allow reg files */
  1865.         (sb1->st_mode & 077) == 0 &&    /* Owner only perms */
  1866.         sb1->st_nlink == sb2->st_nlink &&    /* # hard links same... */
  1867.         sb1->st_nlink == 1 &&        /* and only 1 */
  1868.         sb1->st_uid == sb2->st_uid &&    /* owner and ... */
  1869.         sb1->st_gid == sb2->st_gid &&    /* group unchanged */
  1870.         sb1->st_mtime == sb2->st_mtime &&    /* Unmodified between stats */
  1871.         sb1->st_ctime == sb2->st_ctime);    /* Inode unchanged.  Hopefully
  1872.                            a catch-all paranoid test */
  1873. }
  1874.  
  1875. #if MACH
  1876. /*
  1877.  * Twiddle symbolic/RFS link following on/off.  This is a no-op in a non
  1878.  * CMUCS/MACH environment.  Also, the setmodes/getmodes interface is used
  1879.  * mainly because it is simpler than using table(2) directly.
  1880.  */
  1881. #include <sys/table.h>
  1882.  
  1883. int link_nofollow(on)
  1884. int on;
  1885. {
  1886.     static int modes = -1;
  1887.  
  1888.     if (modes == -1 && (modes = getmodes()) == -1)
  1889.         return(-1);
  1890.     if (on)
  1891.         return(setmodes(modes | UMODE_NOFOLLOW));
  1892.     return(setmodes(modes));
  1893. }
  1894. #else    /* MACH */
  1895. /*ARGSUSED*/
  1896. int link_nofollow(on)
  1897. int on;
  1898. {
  1899.     return(0);
  1900. }
  1901. #endif    /* MACH */
  1902.